using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace CodeGenTest
{
    public abstract class Expr
    {
        public abstract void Eval(ILGenerator ilg);
    }

    public class AddOp : Expr
    {
        private Expr leftSide;
        private Expr rightSide;
        

        public AddOp(Expr leftSide, Expr rightSide)
        {
            this.leftSide = leftSide;
            this.rightSide = rightSide;
        }

        public override void Eval(ILGenerator ilg)
        {
            leftSide.Eval(ilg);
            rightSide.Eval(ilg);
            ilg.Emit(OpCodes.Add);
        }

        public override string ToString()
        {
            return "(" + leftSide + "+" + rightSide + ")";
        }
    }

    public class MultiPly : Expr
    {
        private Expr leftSide;
        private Expr rightSide;


        public MultiPly(Expr leftSide, Expr rightSide)
        {
            this.leftSide = leftSide;
            this.rightSide = rightSide;
        }

        public override void Eval(ILGenerator ilg)
        {
            leftSide.Eval(ilg);
            rightSide.Eval(ilg);
            ilg.Emit(OpCodes.Mul);
        }

        public override string ToString()
        {
            return leftSide + "*" + rightSide;
        }
    }

    public class Value : Expr
    {
        private int val;

        public Value(int val)
        {
            this.val = val;
        }

        public override void Eval(ILGenerator ilg)
        {
            ilg.Emit(OpCodes.Ldc_I4, val);
        }

        public override string ToString()
        {
            return val.ToString();
        }
    }

    public class RandomValue : Expr
    {
        public static Random random = new Random();
        public static Random rnd
        {
            get{return random;}        
        }

        public RandomValue()
        {
            random = new Random();
        }

        public override void Eval(ILGenerator ilg)
        {
            ilg.Emit(OpCodes.Ldind_I4, 23);
            ilg.Emit(OpCodes.Stloc_1);
            ilg.Emit(OpCodes.Ldsfld, typeof(RandomValue).GetField("random"));
            ilg.EmitCall(OpCodes.Callvirt, typeof(Random).GetMethod("Next", new Type[1]{typeof(int)}), null);
            
        }

        public override string ToString()
        {
            return "Rand()";
        }
    }

    /*public class RandomWrapper
    {
        private Random random;


        public RandomWrapper()
        {
            this.random = new Random();
        }

        public int Next()
        {
            return random.Next();
        }
    }*/
}
